home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / KPlib 1.3.5 / KPString.cxx < prev    next >
Text File  |  1995-12-17  |  13KB  |  499 lines

  1. // A module of KPlib v1.3.5.
  2. // Written by Keith Pomakis during the summer of 1994.
  3. // Released to the public domain on October 10, 1994.
  4.  
  5. #include <iostream.h>
  6. #include <stdlib.h>
  7. #include <iomanip.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include "KPbasic.h"
  11. #include "KPString.h"
  12. #include "KPList.h"
  13.  
  14. const int KPString::max_token_size = 200;
  15. const int KPString::max_line_size = 600;
  16. KPString::Data KPString::null_data;
  17.  
  18. /****************************************************************************/
  19.  
  20. KPString::Data *
  21. KPString::new_data(int length)
  22. {
  23.     if (length > 0) {
  24.         Data *data = (Data *) malloc(sizeof(Data) + length);
  25.         check_mem(data);
  26.         data->ref_count = 0;
  27.         data->length = length;
  28.         data->chars[length] = '\0';
  29.         return data;
  30.     }
  31.     else
  32.         return &null_data;
  33. }
  34.  
  35. void
  36. KPString::replace_data(int length)
  37. {
  38.     if (length == my_data->length && my_data->ref_count <= 1)
  39.         return;
  40.  
  41.     if (my_data != &null_data && --my_data->ref_count == 0)
  42.         free(my_data);
  43.  
  44.     if (length > 0) {
  45.         my_data = (Data *) malloc(sizeof(Data) + length);
  46.         check_mem(my_data);
  47.         my_data->ref_count = 1;
  48.         my_data->length = length;
  49.         my_data->chars[length] = '\0';
  50.     }
  51.     else
  52.         my_data = &null_data;
  53. }
  54.  
  55. void
  56. KPString::replace_data(Data *data)
  57. {
  58.     if (my_data != &null_data && --my_data->ref_count == 0)
  59.         free(my_data);
  60.  
  61.     if (data != &null_data)
  62.         data->ref_count++;
  63.     my_data = data;
  64. }
  65.  
  66. void
  67. KPString::make_unique()
  68. {
  69.     if (my_data->ref_count > 1) {
  70.         Data *data = new_data(length());
  71.         ::memcpy(data->chars, chars(), length());
  72.         my_data->ref_count--;
  73.         my_data = data;
  74.         my_data->ref_count++;
  75.     }
  76. }
  77.  
  78. /****************************************************************************/
  79.  
  80. istream &
  81. operator>>(istream &stream, KPString &s)
  82. {
  83.     char buffer[KPString::max_token_size+1];
  84.  
  85.     stream >> setw(KPString::max_token_size) >> buffer;
  86.     if (stream) {
  87.         const int new_length = ::strlen(buffer);
  88.         s.replace_data(new_length);
  89.         ::memcpy(s.chars(), buffer, new_length);
  90.     }
  91.     else
  92.         s.replace_data(0);
  93.  
  94.     return stream;
  95. }
  96.  
  97. /****************************************************************************/
  98.  
  99. KPString
  100. operator+(const char *s1, const KPString &s2)
  101. {
  102.     const int s1_length = ::strlen(s1);
  103.  
  104.     if (s1_length == 0)
  105.         return s2;
  106.     else {
  107.         KPString newstring;
  108.         newstring.replace_data(s1_length + s2.length());
  109.         ::memcpy(newstring.chars(), s1, s1_length);
  110.         ::memcpy(&(newstring.chars())[s1_length], s2.chars(), s2.length());
  111.         return newstring;
  112.     }
  113. }
  114.  
  115. /****************************************************************************/
  116.  
  117. KPString
  118. KPString::operator+(const KPString &s) const
  119. {
  120.     if (length() == 0)
  121.         return s;
  122.     else if (s.length() == 0)
  123.         return *this;
  124.     else {
  125.         KPString newstring;
  126.         newstring.replace_data(length() + s.length());
  127.         ::memcpy(newstring.chars(), chars(), length());
  128.         ::memcpy(&(newstring.chars())[length()], s.chars(), s.length());
  129.         return newstring;
  130.     }
  131. }
  132.  
  133. /****************************************************************************/
  134.  
  135. KPString
  136. KPString::operator+(const char *s) const
  137. {
  138.     const int s_length = ::strlen(s);
  139.  
  140.     if (s_length == 0)
  141.         return *this;
  142.     else {
  143.         KPString newstring;
  144.         newstring.replace_data(length() + s_length);
  145.         ::memcpy(newstring.chars(), chars(), length());
  146.         ::memcpy(&(newstring.chars())[length()], s, s_length);
  147.         return newstring;
  148.     }
  149. }
  150.  
  151. /****************************************************************************/
  152.  
  153. bool
  154. KPString::is_whitespace() const
  155. {
  156.     if (my_data == &null_data)
  157.         return false;
  158.  
  159.     for (register const char *p = chars(); *p; p++)
  160.         if (!isspace(*p))
  161.             return false;
  162.  
  163.     return true;
  164. }
  165.  
  166. /****************************************************************************/
  167.  
  168. KPString
  169. KPString::substr(int index, int len) const
  170. {
  171.     // A negative index specifies an index from the right of the string.
  172.     if (index < 0)
  173.         index += length();
  174.  
  175.     // A length of -1 specifies the rest of the string.
  176.     if (len == -1)
  177.         len = length() - index;
  178.  
  179.     if (index<0 || index>=length() || len<0 || len>length()-index)
  180.         invalid_args_error("substr()");
  181.  
  182.     KPString newstring;
  183.     newstring.replace_data(len);
  184.     ::memcpy(newstring.chars(), &chars()[index], len);
  185.  
  186.     return newstring;
  187. }
  188.  
  189. /****************************************************************************/
  190.  
  191. KPString &
  192. KPString::cut(int index, int len)
  193. {
  194.     if (len == 0)
  195.         return *this;
  196.  
  197.     // A negative index specifies an index from the right of the string.
  198.     if (index < 0)
  199.         index += length();
  200.  
  201.     // A length of -1 specifies the rest of the string.
  202.     if (len == -1)
  203.         len = length() - index;
  204.  
  205.     if (index<0 || index>=length() || len<0 || len>length()-index)
  206.         invalid_args_error("cut()");
  207.  
  208.     Data *data = new_data(length() - len);
  209.     if (index > 0)
  210.         ::memcpy(data->chars, chars(), index);
  211.     ::strcpy(&data->chars[index], &chars()[index+len]);
  212.     replace_data(data);
  213.  
  214.     return *this;
  215. }
  216.  
  217. /****************************************************************************/
  218.  
  219. KPString &
  220. KPString::replace_substr(const KPString &s, int index, int len)
  221. {
  222.     // A negative index specifies an index from the right of the string.
  223.     if (index < 0)
  224.         index += length();
  225.  
  226.     // A length of -1 specifies the rest of the string.
  227.     if (len == -1)
  228.         len = length() - index;
  229.  
  230.     if (index<0 || index>=length() || len<0 || len>length()-index)
  231.         invalid_args_error("replace_substr()");
  232.  
  233.     if (len == s.length() && my_data->ref_count == 1)
  234.         ::memcpy(&chars()[index], s.chars(), len);
  235.     else {
  236.         Data *data = new_data(length() - len + s.length());
  237.         if (index > 0)
  238.             ::memcpy(data->chars, chars(), index);
  239.         if (s.length() > 0)
  240.             ::memcpy(&data->chars[index], s.chars(), s.length());
  241.         ::strcpy(&data->chars[index+s.length()], &chars()[index+len]);
  242.         replace_data(data);
  243.     }
  244.  
  245.     return *this;
  246. }
  247.  
  248. /****************************************************************************/
  249.  
  250. KPString &
  251. KPString::replace_substr(const char *s, int index, int len)
  252. {
  253.  
  254.     // A negative index specifies an index from the right of the string.
  255.     if (index < 0)
  256.         index += length();
  257.  
  258.     // A length of -1 specifies the rest of the string.
  259.     if (len == -1)
  260.         len = length() - index;
  261.  
  262.     if (index<0 || index>=length() || len<0 || len>length()-index)
  263.         invalid_args_error("replace_substr()");
  264.  
  265.     const int s_length = ::strlen(s);
  266.  
  267.     if (len == s_length && my_data->ref_count == 1)
  268.         ::memcpy(&chars()[index], s, len);
  269.     else {
  270.         Data *data = new_data(length() - len + s_length);
  271.         if (index > 0)
  272.             ::memcpy(data->chars, chars(), index);
  273.         if (s_length > 0)
  274.             ::memcpy(&data->chars[index], s, s_length);
  275.         ::strcpy(&data->chars[index+s_length], &chars()[index+len]);
  276.         replace_data(data);
  277.     }
  278.  
  279.     return *this;
  280. }
  281.  
  282. /****************************************************************************/
  283.  
  284. KPString &
  285. KPString::insert(const KPString &s, int index)
  286. {
  287.     // A negative index specifies an index from the right of the string.
  288.     if (index < 0)
  289.         index += length();
  290.  
  291.     if (index < 0 || index >= length())
  292.         invalid_index_error("insert()");
  293.  
  294.     if (s.length() > 0) {
  295.         Data *data = new_data(length() + s.length());
  296.         if (index > 0)
  297.             ::memcpy(data->chars, chars(), index);
  298.         ::memcpy(&data->chars[index], s.chars(), s.length());
  299.         ::strcpy(&data->chars[index+s.length()], &chars()[index]);
  300.         replace_data(data);
  301.     }
  302.  
  303.     return *this;
  304. }
  305.  
  306. /****************************************************************************/
  307.  
  308. KPString &
  309. KPString::insert(const char *s, int index)
  310. {
  311.     // A negative index specifies an index from the right of the string.
  312.     if (index < 0)
  313.         index += length();
  314.  
  315.     if (index < 0 || index >= length())
  316.         invalid_index_error("insert()");
  317.  
  318.     const int s_length = ::strlen(s);
  319.  
  320.     if (s_length > 0) {
  321.         Data *data = new_data(length() + s_length);
  322.         if (index > 0)
  323.             ::memcpy(data->chars, chars(), index);
  324.         ::memcpy(&data->chars[index], s, s_length);
  325.         ::strcpy(&data->chars[index+s_length], &chars()[index]);
  326.         replace_data(data);
  327.     }
  328.  
  329.     return *this;
  330. }
  331.  
  332. /****************************************************************************/
  333.  
  334. KPString &
  335. KPString::to_upper()
  336. {
  337.     make_unique();
  338.  
  339.     for (register char *p = chars(); *p; p++)
  340.         if (islower(*p))
  341.             *p = toupper(*p);
  342.  
  343.     return *this;
  344. }
  345.  
  346. /****************************************************************************/
  347.  
  348. KPString &
  349. KPString::to_lower()
  350. {
  351.     make_unique();
  352.  
  353.     for (register char *p = chars(); *p; p++)
  354.         if (isupper(*p))
  355.             *p = tolower(*p);
  356.  
  357.     return *this;
  358. }
  359.  
  360. /****************************************************************************/
  361.  
  362. int
  363. KPString::index_of(const char *s, int start_index) const
  364. {
  365.     // A negative index specifies an index from the right of the string.
  366.     if (start_index < 0)
  367.         start_index += length();
  368.  
  369.     if (start_index < 0 || start_index >= length())
  370.         invalid_index_error("index_of()");
  371.  
  372.     const char *index;
  373.     if (!(index = strstr(&chars()[start_index], s)))
  374.         return -1;
  375.     else
  376.         return index - chars();
  377. }
  378.  
  379. /****************************************************************************/
  380.  
  381. int
  382. KPString::index_of(char c, int start_index) const
  383. {
  384.     // A negative index specifies an index from the right of the string.
  385.     if (start_index < 0)
  386.         start_index += length();
  387.  
  388.     if (start_index < 0 || start_index >= length())
  389.         invalid_index_error("index_of()");
  390.  
  391.     const char *index;
  392.  
  393.     if (c == '\0')
  394.         return -1;
  395.  
  396.     else if (!(index = (char *) ::memchr(&chars()[start_index], c,
  397.                                          length()-start_index)))
  398.         return -1;
  399.     else
  400.         return index - chars();
  401. }
  402.  
  403. /****************************************************************************/
  404.  
  405. KPList<KPString>
  406. KPString::tokens(const char *separators) const
  407. {
  408.     KPList<KPString> list;
  409.     int token_length, index = 0;
  410.  
  411.     do {
  412.         index += ::strspn(&chars()[index], separators);
  413.         token_length = ::strcspn(&chars()[index], separators);
  414.         if (token_length > 0)
  415.             list.add_to_tail(substr(index, token_length));
  416.         index += token_length;
  417.     } while (token_length > 0);
  418.  
  419.     return list;
  420. }
  421.  
  422. /****************************************************************************/
  423.  
  424. KPList<KPString> KPString::tokens(char separator) const
  425. {
  426.     char separators[2];
  427.     separators[0] = separator;
  428.     separators[1] = '\0';
  429.     return tokens(separators);
  430. }
  431.  
  432. /****************************************************************************/
  433.  
  434. KPString &
  435. KPString::read_line(istream &stream)
  436. {
  437.     char buffer[max_line_size+1];
  438.     stream.getline(buffer, max_line_size);
  439.     const int new_length = ::strlen(buffer);
  440.     Data *data = new_data(new_length);
  441.     ::memcpy(data->chars, buffer, new_length);
  442.     replace_data(data);
  443.  
  444.     return *this;
  445. }
  446.  
  447. /****************************************************************************/
  448.  
  449. KPString &
  450. KPString::read_token(istream &stream, const char *separators)
  451. {
  452.     register int c;
  453.     const int num_of_separators = ::strlen(separators);
  454.  
  455.     // Scan for the first character of the token.
  456.     do {
  457.         c = stream.get();
  458.         if (c == EOF) {
  459.             replace_data(0);
  460.             return *this;
  461.         }
  462.     } while (::memchr(separators, c, num_of_separators));
  463.  
  464.     register int i = 0;
  465.     char buffer[max_token_size];
  466.  
  467.     // Read in the token.
  468.     do {
  469.         buffer[i++] = c;
  470.         c = stream.get();
  471.     } while (c != EOF && !::memchr(separators, c, num_of_separators));
  472.  
  473.     stream.putback(c);
  474.     replace_data(i);
  475.     ::memcpy(chars(), buffer, i);
  476.  
  477.     return *this;
  478. }
  479.  
  480. /****************************************************************************/
  481.  
  482. void
  483. KPString::invalid_args_error(const char *fname)
  484. {
  485.     cerr << "KPString::" << fname << " - invalid arguments\n";
  486.     exit(EXIT_FAILURE);
  487. }
  488.  
  489. /****************************************************************************/
  490.  
  491. void
  492. KPString::invalid_index_error(const char *fname)
  493. {
  494.     cerr << "KPString::" << fname << " - invalid index\n";
  495.     exit(EXIT_FAILURE);
  496. }
  497.  
  498. /****************************************************************************/
  499.